package com.deer.wms.instock.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.deer.wms.ASN.manage.dao.AsnDetailMapper;
import com.deer.wms.ASN.manage.dao.AsnMasterMapper;
import com.deer.wms.ASN.manage.model.asn.AsnDetail;
import com.deer.wms.ASN.manage.model.asn.AsnMaster;
import com.deer.wms.ASN.manage.model.qc.QcRecord;
import com.deer.wms.base.system.dao.ErpBackRecordMapper;
import com.deer.wms.base.system.dao.SuppInfoMapper;
import com.deer.wms.base.system.model.Cell.CellInfo;
import com.deer.wms.base.system.model.ErpBackRecord;
import com.deer.wms.base.system.model.Item.ItemInfo;
import com.deer.wms.base.system.model.OrderDetailBO;
import com.deer.wms.base.system.model.OrderToErpBO;
import com.deer.wms.base.system.model.Supplier.SupplierInfo;
import com.deer.wms.base.system.service.CellInfoService;
import com.deer.wms.base.system.service.ItemInfoService;
import com.deer.wms.instock.constant.InStockConstant;
import com.deer.wms.instock.dao.TransferBillMapper;
import com.deer.wms.instock.model.Allot.TransferBillCriteria;
import com.deer.wms.instock.model.transfer.TransferBill;
import com.deer.wms.instock.service.TransferBillService;
import com.deer.wms.inventory.constant.InventoryConstant;
import com.deer.wms.inventory.model.Inventory.InventoryTransact;
import com.deer.wms.inventory.model.Inventory.ItemBatch;
import com.deer.wms.inventory.service.InventoryTransactService;
import com.deer.wms.inventory.service.ItemBatchService;
import com.deer.wms.project.root.core.result.CommonCode;
import com.deer.wms.project.root.exception.ServiceException;
import com.deer.wms.project.root.service.SuperService;
import com.deer.wms.project.root.service.SuperServiceImpl;
import com.deer.wms.project.root.util.DateUtils;
import com.deer.wms.project.root.util.HttpClient;
import com.deer.wms.project.root.util.StringUtils;
import com.deer.wms.system.manage.constant.SystemManageConstant;
import com.deer.wms.system.manage.model.ware.WareInfo;
import com.deer.wms.system.manage.service.CodeRuleService;
import com.deer.wms.system.manage.service.DeptService;
import com.deer.wms.system.manage.service.WareInfoService;
import com.google.common.base.Preconditions;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.jsoup.helper.DataUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * @author : wei
 * @since : 2022-01-08 20:43:41
 **/
@Service
@Transactional
public class TransferBillServiceImpl extends SuperServiceImpl<TransferBillMapper, TransferBill> implements TransferBillService {

    @Autowired
    private CodeRuleService codeRuleService;
    @Autowired
    private InventoryTransactService inventoryTransactService;
    @Autowired
    private WareInfoService wareInfoService;
    @Autowired
    private CellInfoService cellInfoService;
    @Autowired
    private ItemInfoService itemInfoService;
    @Autowired
    private ItemBatchService itemBatchService;
    @Autowired
    private TransferBillMapper transferBillMapper;
    @Autowired
    private AsnMasterMapper asnMasterMapper;
    @Autowired
    private AsnDetailMapper asnDetailMapper;
    @Autowired
    private ErpBackRecordMapper erpBackRecordMapper;


    @Override
    public List<TransferBill> saveAndConfirmTransferBill(List<TransferBill> transferBills) {
        List<TransferBill> list = this.createTransferBill(transferBills);
        // 这里直接装箱单确认了
        return this.confirmTransferBill(list);
    }

    @Override
    public List<TransferBill> createTransferBill(List<TransferBill> transferBills) {
        for (TransferBill transferBill : transferBills) {
            //Step1.各类数据数据校验，不合法给与异常信息提示
            //仓库 来源库位  目标库位  来源容器  目标容器  物料  批次
            this.validateAndPrepareTransferData(transferBill);

            //Step2.组装收货单数据
            //单据号
            transferBill.setTransferBillCode(codeRuleService.generateCode(SystemManageConstant.CODE_RULE_TRANS));
            //状态
            transferBill.setState(InStockConstant.TRANS_STATE_INIT);
        }
        //Step3.统一保存
        this.saveBatch(transferBills);

        return transferBills;
    }


    @Override
    public List<TransferBill> confirmTransferBill(List<TransferBill> transferBills) {
        for (TransferBill transferBill : transferBills) {
            //Step1.判断转移单是否满足确认的条件 修改状态
            if (ObjectUtil.notEqual(InStockConstant.TRANS_STATE_INIT, transferBill.getState())) {
                throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "转移单不为新建状态，不可确认!");
            }
            transferBill.setState(InStockConstant.TRANS_STATE_FINISHED);
            transferBill.setConfirmTime(DateUtil.now());

            //Step2.生成库存事务请求 并提交(事务提交，修改库存)
            InventoryTransact inventoryTransact = this.toStockRequest(transferBill);
            inventoryTransactService.run(inventoryTransact);
        }
        //Step3.批次保存转移单
        this.saveOrUpdateBatch(transferBills);
//        if(true) {throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "xx");}
        return transferBills;
    }

    /**
     * 校验转移单的各类数据是否合法
     *
     * @param transferBill 转移单
     */
    private void validateAndPrepareTransferData(TransferBill transferBill) {



        //仓库
        WareInfo wareInfo = wareInfoService.getOneByField("ware_id", transferBill.getWareId());
        Preconditions.checkNotNull(wareInfo, "根据仓库id[%s]获取仓库失败!", new Object[]{transferBill.getWareId()});
        transferBill.setWareCode(wareInfo.getWareCode());
        transferBill.setWareName(wareInfo.getWareName());
        //来源库位 所有类型都需要校验
        CellInfo fromCellInfo = cellInfoService.findByCodeAndWareId(transferBill.getFromCellCode(), transferBill.getWareId());
        Preconditions.checkNotNull(fromCellInfo, "根据仓库id[%s],库位[%s]获取来源库位失败!", new Object[]{transferBill.getWareId(), transferBill.getFromCellCode()});
        //目标库位
        //上架，转移，拣货 需要校验
        CellInfo toCellInfo = cellInfoService.findByCodeAndWareId(transferBill.getToCellCode(), transferBill.getWareId());
        Preconditions.checkNotNull(toCellInfo, "根据仓库id[%s],库位[%s]获取目标库位失败!", new Object[]{transferBill.getWareId(), transferBill.getToCellCode()});
        //物料
        ItemInfo itemInfo = itemInfoService.getOneByField("item_code", transferBill.getItemCode());
        Preconditions.checkNotNull(itemInfo, "根据物料编码[%s]获取物料失败!", new Object[]{transferBill.getItemCode()});
        transferBill.setItemName(itemInfo.getItemName());
//        transferBill.setPackDetailId(itemInfo.getPackCode());
        //批次
        ItemBatch itemBatch = itemBatchService.getOneByField("batch_name", transferBill.getBatchName());
        Preconditions.checkNotNull(itemBatch, "根据物料[%s],批次号[%s]获取批次失败!", new Object[]{transferBill.getItemCode(), transferBill.getBatchName()});
        transferBill.setBatchId(itemBatch.getBatchId());
        transferBill.setBatchName(itemBatch.getBatchName());
        //来源容器
        //上架 转移 拣货 分拣 。
        if (ObjectUtil.notEqual(InStockConstant.TRANS_TYPE_PACK_BOX, transferBill.getBillType())) {
            if (StringUtils.isEmpty(transferBill.getFromBoxCode())) {
                throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "来源容器不允许为空");
            }
        }

        //TODO: 库存确认
        //目标容器
        //需要有目标容器：装箱 分拣
        if (InStockConstant.TRANS_TYPE_PACK_BOX.equals(transferBill.getBillType()) || InStockConstant.TRANS_TYPE_PICK2.equals(transferBill.getBillType())) {
            if (StringUtils.isEmpty(transferBill.getToBoxCode())) {
                throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "目标容器不允许为空");
            }
        } else {
            //不能有目标容器：上架 转移 拣货
            if (StringUtils.isNotEmpty(transferBill.getToBoxCode())) {
                throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "不允许有目标容器");
            }
        }
    }

    private InventoryTransact toStockRequest(TransferBill transferBill) {
        InventoryTransact inventoryTransact = new InventoryTransact();
        //Step1.准备数据
        //仓库
        inventoryTransact.setWareId(transferBill.getWareId());
        inventoryTransact.setWareName(transferBill.getWareName());
        //库位
        inventoryTransact.setFromCellCode(transferBill.getFromCellCode());
        inventoryTransact.setToCellCode(transferBill.getToCellCode());
        //容器
        inventoryTransact.setFromBoxCode(transferBill.getFromBoxCode());
        inventoryTransact.setToBoxCode(transferBill.getToBoxCode());
        //物料
        inventoryTransact.setItemCode(transferBill.getItemCode());
        inventoryTransact.setItemName(transferBill.getItemName());
        //批次
        inventoryTransact.setFromBatchId(transferBill.getBatchId());
        inventoryTransact.setFromBatchName(transferBill.getBatchName());
        inventoryTransact.setToBatchId(transferBill.getBatchId());
        inventoryTransact.setToBatchName(transferBill.getBatchName());
        //数量
        inventoryTransact.setToQuantity(transferBill.getQty().doubleValue());
        //包装 转换率
        inventoryTransact.setFromPackDetailId(transferBill.getPackDetailId());
        inventoryTransact.setToPackDetailId(transferBill.getPackDetailId());
        inventoryTransact.setToTransRatio(new Double(1));
        inventoryTransact.setFromTransRatio(new Double(1));
        //创建人 时间
        inventoryTransact.setCreateUserId(transferBill.getConfirmUserId());
        inventoryTransact.setCreateUserName(transferBill.getConfirmUserName());
        inventoryTransact.setCreateTime(DateUtil.now());
        //事务类型
        inventoryTransact.setTransactType(handleTransactType(transferBill.getBillType()));
        //来源单据号
        inventoryTransact.setBillNo(transferBill.getTransferBillCode());
        //冻结标识
        inventoryTransact.setState(transferBill.getFreezeFlag());

        //Step2.保存，返回
        inventoryTransactService.save(inventoryTransact);
        return inventoryTransact;
    }

    /**
     * 转移单类型到库存类型的转换
     * @param billType 转移单类型
     * @return 库存事物类型
     */
    private Integer handleTransactType(Integer billType) {
        Integer transactType = null;
        switch (billType) {
            case 0: //InStockConstant.TRANS_TYPE_PACK_BOX
                transactType = InventoryConstant.TRANSACT_TYPE_PACK;
                break;
            case 2: //InStockConstant.TRANS_TYPE_UPPER
                transactType = InventoryConstant.TRANSACT_TYPE_UP;
                break;
            case 4: //InStockConstant.TRANS_TYPE_MOVE
                transactType = InventoryConstant.TRANSACT_TYPE_MOVE;
                break;
            case 6: //InStockConstant.TRANS_TYPE_PICK
                transactType = InventoryConstant.TRANSACT_TYPE_PICK;
                break;
//            case 8: //InStockConstant.TRANS_TYPE_PICK2
//                transactType = InventoryConstant.TRANSACT_TYPE_PACK;-
//                break;
            default:
                throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "未匹配到转移单类型");
        }
        return transactType;
    }

    @Override
    public List<TransferBill> selectBillList(TransferBillCriteria transferBillCriteria) {
        // 返回查询的数据
        return transferBillMapper.selectBillList(transferBillCriteria);
    }

    @Override
    public String billToErpNew(String billNo, String fromBoxCode,Integer deptId) {
        try {
            //请求token
            MultiValueMap<String, String> stringMultiValueMap = new LinkedMultiValueMap<>();
            stringMultiValueMap.add("client_id", "KingdeeK3_Rggy_AppClient_Test");
            stringMultiValueMap.add("client_secret", "TekE%dAISMCvwk7V");
            stringMultiValueMap.add("grant_type", "password");
            stringMultiValueMap.add("username", "epichust");
            stringMultiValueMap.add("password", "hK@vmz0YI1e^thtB");
            String tokenUrl = "https://syecrg.sieyuan.com:44310/connect/token";
            String clientRg = HttpClient.clientRg(tokenUrl, HttpMethod.POST, stringMultiValueMap);
            JSONObject jsonObject = JSONObject.parseObject(clientRg);
            String token = jsonObject.getString("access_token");
            System.out.println(token);

            if(token != null){

                QueryWrapper<AsnMaster> amqw = Wrappers.query();
                AsnMaster asnMaster = asnMasterMapper.selectOne(amqw.eq("bill_no", billNo));

//                    if(asnMaster != null){
                OrderToErpBO bo = new OrderToErpBO();
                List<OrderDetailBO> pd = new ArrayList<>();

//                List<TransferBill> transferBills = transferBillMapper.findListByBillNo(billNo);
//                for(TransferBill tb : transferBills){
                QueryWrapper<TransferBill> tbqw = Wrappers.query();
                TransferBill tb = transferBillMapper.selectOne(tbqw.eq("to_box_code", fromBoxCode));

                    OrderDetailBO db = new OrderDetailBO();
                    QueryWrapper<AsnDetail> adqw = Wrappers.query();
                    AsnDetail asnDetail = asnDetailMapper.selectOne(adqw.eq("detail_no", tb.getUda2()));
                    db.setSourceBillDetailRowIndex(asnDetail.getCreateUserId());
                    db.setAuxPropId(asnDetail.getUpperPackDetailId());
                    db.setBatchNo(asnDetail.getModel());
                    db.setQty(tb.getQty().doubleValue());
                    db.setMtoNo(asnDetail.getPackCode());
                    db.setRemark(asnDetail.getMemo());
                    db.setProductionDate(asnDetail.getAsnUdfDs2());
                    db.setShelfLifeDays(Integer.parseInt(asnDetail.getAsnUdfDs3()));
                    db.setStockPlaceId(1);
                    db.setBatchNo(tb.getBatchName());
                    bo.setBillTypeId(Integer.parseInt(asnDetail.getUpperPackDescribe()));
                    pd.add(db);
//                }
                bo.setBillNo(tb.getTransferBillCode());
                bo.setBillDate(new SimpleDateFormat("yyyy-MM-dd").format(new SimpleDateFormat("yyyy-MM-dd").parse(asnMaster.getExpectTime())));
                bo.setSourceBillTypeId(asnMaster.getBillType());
                bo.setStockId(5924);
                bo.setRemark(asnMaster.getMemo());
                bo.setDetails(pd);
                bo.setDeptId(deptId);

                //调用erp接口获取数据
                CloseableHttpClient client = HttpClients.createDefault();
                URIBuilder uriBuilder = new URIBuilder("https://syecrg.sieyuan.com:44398/api/IMBill/PushIMBill");
                HttpPost post = new HttpPost(uriBuilder.build());
                ErpBackRecord erpRecord = new ErpBackRecord();
                erpRecord.setCode(billNo);
                erpRecord.setParam(JSON.toJSONString(bo));
                StringEntity myEntity = new StringEntity(JSON.toJSONString(bo), "UTF-8");// 构造请求数据
                post.setHeader("Content-Type", "application/json");
                post.addHeader("Authorization", "Bearer " + token);
                post.setEntity(myEntity);// 设置请求体
                String responseContent = null; // 响应内容
                CloseableHttpResponse response = null;
                try {
                    response = client.execute(post);
//                    System.out.println("response===>" + JSON.toJSONString(response));
                    HttpEntity entity = response.getEntity();
                    InputStream content = entity.getContent();
                    String msg = inputStream2String(content);
                    if (response.getStatusLine().getStatusCode() == 200) {
                        System.out.println("上架回传erp成功");
                        erpRecord.setCode("200");
                        erpRecord.setState(2);
                        erpRecord.setMsg("上架回传erp成功");
                        erpBackRecordMapper.insert(erpRecord);
                        return msg;
                    }else{
                        System.out.println("上架回传erp报错");
                        erpRecord.setCode(String.valueOf(response.getStatusLine().getStatusCode()));
                        erpRecord.setState(1);
                        erpRecord.setMsg(msg);
                        erpBackRecordMapper.insert(erpRecord);
                        System.out.println(erpRecord.getParam());
                        throw new Exception(msg);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }  finally {
                    try {
                        if (response != null)
                            response.close();

                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {
                        try {
                            if (client != null)
                                client.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }

            }else {
                throw new Exception("token的取值为空");
            }

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return null;
    }

    public   static   String   inputStream2String(InputStream   is)   throws   IOException{
        ByteArrayOutputStream baos   =   new ByteArrayOutputStream();
        int   i=-1;
        while((i=is.read())!=-1){
            baos.write(i);
        }
        return   baos.toString();
    }

}
